//
// Created by goksu on 4/6/19.
// rasterizer.hpp
//

#pragma once //确保这个头文件只被编译一次

#include "Triangle.hpp"
#include <algorithm>
#include <eigen3/Eigen/Eigen>
using namespace Eigen;

namespace rst {
enum class Buffers
{
    Color = 1,
    Depth = 2
    // 枚举类，定义两个缓冲区类型，
    // 颜色缓冲区1， 深度缓冲区2， 
    // 用来存储渲染过程当中的数据
};

// 重载运算符 and 和 or
inline Buffers operator|(Buffers a, Buffers b)
{
    return Buffers((int)a | (int)b);
}

inline Buffers operator&(Buffers a, Buffers b)
{
    return Buffers((int)a & (int)b);
}

// 枚举类，定义最基本的图元类型
enum class Primitive
{
    Line,
    Triangle
};

/*
For the curious : The draw function takes 
two buffer id's as its arguments.
These two structs make sure that 
if you mix up with their orders, the
compiler won't compile it. 
Aka : Type safety
*/

// 增强类型安全性， 防止使用id的时候混淆顺序
struct pos_buf_id
{
    int pos_id = 0;
};

struct ind_buf_id
{
    int ind_id = 0;
};

// 光栅化器类，用于处理渲染过程。 构造函数接受宽度和高度参数，
// 初始化帧缓冲区大小
class rasterizer
{
  public:
    rasterizer(int w, int h);
    //加载顶点位置 和 索引数据，返回对应的id
    pos_buf_id load_positions(const std::vector<Eigen::Vector3f>& positions);
    ind_buf_id load_indices(const std::vector<Eigen::Vector3i>& indices);
    
    //将内部的模型矩阵作为参数船体给光栅化器rasterizer
    void set_model(const Eigen::Matrix4f& m);
    //将视图变换矩阵设为内部视图矩阵
    void set_view(const Eigen::Matrix4f& v);
    //将内部的投影矩阵设为给定矩阵p，并传递给光栅化器rasterizer
    void set_projection(const Eigen::Matrix4f& p);
    //将屏幕像素点(x,y)设为(r,g,b)颜色，并写入相应的帧缓冲区位置
    void set_pixel(const Eigen::Vector3f& point, const Eigen::Vector3f& color);

    //清楚缓冲区
    void clear(Buffers buff);
    //根据给定的位置和索引缓冲区以及图元类型，
    //执行绘制操作
    void draw(pos_buf_id pos_buffer, ind_buf_id ind_buffer, Primitive type);

    std::vector<Eigen::Vector3f>& frame_buffer() { return frame_buf; }
    //绘制线段和三角形
  private:
    void draw_line(Eigen::Vector3f begin, Eigen::Vector3f end);
    void rasterize_wireframe(const Triangle& t);

  private:
  //mvp 三个变换矩阵 私有成员 模型 视图 投影
    Eigen::Matrix4f model; //调整物体 （平移 旋转 缩放）
    Eigen::Matrix4f view;  //调整相机 （调整相机到经典位置）
    Eigen::Matrix4f projection; //把3d坐标映射到2d坐标

    // 用map存储位置和索引缓冲区
    std::map<int, std::vector<Eigen::Vector3f>> pos_buf;
    std::map<int, std::vector<Eigen::Vector3i>> ind_buf;

    //帧缓冲对象，用于存储需要在屏幕上绘制的颜色数据
    std::vector<Eigen::Vector3f> frame_buf; //用于存储渲染的颜色数据。
    std::vector<float> depth_buf; //用于存储每个像素的深度值，确保正确的前后关系。
    int get_index(int x, int y);
    //get_index：根据像素坐标计算在缓冲区中的索引。

    int width, height;

    int next_id = 0;
    int get_next_id() { return next_id++; }
    //get_next_id：用于生成唯一的缓冲区ID。
};
} // namespace rst
